package com.zxmc.server.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.zxmc.aop.BloomFilterAdd;
import com.zxmc.aop.BloomFilterCheck;
import com.zxmc.common.exception.CrawlerFailException;
import com.zxmc.common.result.PageResult;
import com.zxmc.common.utils.BloomFilterUtil;
import com.zxmc.pojo.dto.NovelDto;
import com.zxmc.pojo.dto.NovelQueryDto;
import com.zxmc.pojo.dto.NovelRecommend;
import com.zxmc.pojo.dto.PageNovelQueryDto;
import com.zxmc.pojo.entity.Chapter;
import com.zxmc.pojo.entity.Novel;
import com.zxmc.pojo.entity.NovelType;
import com.zxmc.pojo.vo.NovelVO;
import com.zxmc.server.mapper.NovelMapper;
import com.zxmc.server.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

@Service
@Slf4j
public class NovelServiceImpl implements NovelService {
    @Autowired
    private NovelMapper novelMapper;
    @Autowired
    private ChapterService chapterService;
    @Autowired
    private NovelTypeService novelTypeService;
    @Autowired
    private ReadingHistoryService readingHistoryService;
    @Autowired
    private BookShelfService bookShelfService;
    @Autowired
    private NovelService novelService;
    @Autowired
    private BloomFilterUtil bloomFilterUtil;


    /**
     * 插入小说 ,爬虫
     * @param novelDto
     */

    @Transactional(rollbackFor = Exception.class)
    @Override
    @CacheEvict(value = {"novelPageCache","novelCache"},allEntries = true )
    public void insert(NovelDto novelDto) {
        //插入小说数据
        Novel novel = new Novel();
        BeanUtils.copyProperties(novelDto,novel);
        novelMapper.insert(novel);
        bloomFilterUtil.add(novel.getId().toString());
        //插入章节数据
        List<String> titles = novelDto.getTitles();
        List<String> contents = novelDto.getContents();
//        System.out.println(titles);
//        System.out.println(contents);
        for (int i = 0; i < titles.size()&& i<50; i++) {

            Chapter chapter = Chapter.builder().novelId(novel.getId())
                    .title(titles.get(i))
                    .content(contents.get(i))
                    .chapterOrder(i+1)
                    .build();
            chapterService.insert(chapter);
        }

        //插入类型数据
        List<String> tags = novelDto.getTags();
        for (String tag : tags) {
            NovelType novelType = NovelType.builder()
                    .novelId(novel.getId())
                    .value(tag).build();
            novelTypeService.insert(novelType);
        }
    }

    @BloomFilterCheck
    @Cacheable(value = "novelCache", key = "#novelQueryDto.id != null ? #novelQueryDto.id.toString() : 'defaultKeyForAllNull'")
    @Override
    public List<Novel> list(NovelQueryDto novelQueryDto) {

        return novelMapper.list(novelQueryDto);
    }

    @BloomFilterCheck
    @Cacheable(value = "novelPageCache")
    @Override
    public PageResult page(PageNovelQueryDto pageNovelQueryDto) {
        PageHelper.startPage(pageNovelQueryDto.getPage(),pageNovelQueryDto.getPageSize());
        Page<Novel> page;
        if(pageNovelQueryDto.getTag()==null || pageNovelQueryDto.getTag().isEmpty()) {
            page= novelMapper.page(pageNovelQueryDto);
        }else {
            page=novelMapper.pageByTag(pageNovelQueryDto);
        }

        long total = page.getTotal();
        List<Novel> novels = page.getResult();
        List<NovelVO> novelVOs = getNovelVOs(pageNovelQueryDto, novels, novelTypeService);
        return new PageResult(total,novelVOs);
    }
    @Caching(
            evict = {
                    @CacheEvict(value = "novelCache", key = "#novel.id"),
                    @CacheEvict(value = "novelCache", key = "'defaultKeyForAllNull'"),
                    @CacheEvict(value = "novelPageCache", allEntries = true),
                    @CacheEvict(value = "novelRecommendCache", allEntries = true)
            }
    )
    @Override
    public void update(Novel novel) {
        novelMapper.update(novel);
    }

    @Override
    public void updateCover(Novel novel) {
        novelMapper.update(novel);
    }

    @Cacheable("novelRecommendCache")
    @Override
    public List<NovelRecommend> listRecommend() {
        return novelMapper.listRecommend();
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    @Caching(
            evict = {
                    @CacheEvict(value = "novelCache", key = "#id"),
                    @CacheEvict(value = "novelCache", key = "'defaultKeyForAllNull'")
            }
    )
    public void delete(Integer id) {
        //查找小说
        Novel novel = novelService.listById(id);
        //删除相关的阅读历史
        readingHistoryService.deleteByNovel(novel);
        //删除相关的书架信息
        bookShelfService.deleteAll(novel.getId());
        //删除相关的novelType
        novelTypeService.deleteByNovel(novel);
        //删除小说
        novelMapper.delete(novel);
    }

    @Override
    public List<Integer> listAllIds() {

        return novelMapper.listAllIds();
    }

    @Override
    public List<Novel> listByAuthor(String author) {

        return novelMapper.listByAuthor(author);
    }

//    @Caching(
//            evict = {
//                    @CacheEvict(value = "novelCache", key = "#id"),
//                    @CacheEvict(value = "novelCache", key = "'defaultKeyForAllNull'")
//            }
//    )
    @Override
    public void crawlerById(Integer id) {
        Novel novel = novelService.list(NovelQueryDto.builder().id(id).build()).get(0);
        // 创建一个ProcessBuilder对象，指定要执行的Python脚本和参数
        NovelDto novelDto = crawler(novel.getCrawlerLink());
        Novel novel1 = new Novel();
        BeanUtils.copyProperties(novelDto, novel1);
        novel1.setId(novel.getId());
        // 打印JSON对象
        System.out.println(novelDto.getTitle());

        //调用

        novelService.update(novel1);

    }
    public NovelDto crawler(String url)
    {
        try {
            ProcessBuilder pb = new ProcessBuilder("python", "bishe_back\\src\\main\\resources\\static\\crawer.py",url);

            // 启动进程
            Process process = pb.start();

            // 获取进程的输出流
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));

            // 读取Python脚本的输出
            StringBuilder output = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                output.append(line);
            }
            if(output.toString().isEmpty()) {
                throw new CrawlerFailException("爬虫失败");
            }
            // 等待进程结束
            int exitCode = process.waitFor();
            System.out.println("Python脚本执行完毕，退出码: " + exitCode);
            //            System.out.println(output);
            //             将Python脚本的输出解析为JSON对象
            return JSONObject.parseObject(output.toString(), NovelDto.class);
        }catch (IOException | InterruptedException e) {
            throw new RuntimeException(e);
        }

    }
//    @CacheEvict(value = "novelCache", key = "'defaultKeyForAllNull'")
    @Override
    public void crawlerByUrl(String url) {
        try {
            novelService.insert(crawler(url));
        }catch (DuplicateKeyException e) {
            System.out.println("小说重复");
        }
    }

    @Override
    public Novel listById(Integer id) {
        return novelMapper.listById(id);
    }

    //    @Cacheable("novelVOCache")
    public List<NovelVO> getNovelVOs(PageNovelQueryDto pageNovelQueryDto, List<Novel> novels, NovelTypeService novelTypeService) {
        List<NovelVO> novelVOS = new ArrayList<>();
        for (Novel novel : novels) {
            //复制novel属性
            NovelVO novelVO = new NovelVO();
            BeanUtils.copyProperties(novel,novelVO);
            //赋值tags
            List<NovelType> list = novelTypeService.list(novelVO.getId());
            for (NovelType novelType : list) {
                if (novelVO.getTags() == null) {
                    novelVO.setTags(new ArrayList<>());
                }

                novelVO.getTags().add(novelType.getValue());
            }
            String tag1 = pageNovelQueryDto.getTag();
            boolean flag = tag1 == null || tag1.isEmpty();
            for (String tag : novelVO.getTags()) {
                if(tag1 != null && tag1.equals(tag)) {
                    flag = true;
                    break;
                }
            }
            if(flag) {
                novelVOS.add(novelVO);
            }
        }

        return novelVOS;
    }
}
